using System;
using System.Collections.Generic;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components.Communication
{
    /// <summary></summary>
    [Serializable]
    public class EmailInstruction:InstructionBase
    {
        #region props
        private string _BodyTemplate;
        /// <summary></summary>
        public string BodyTemplate
        {
            get
            {
                return this._BodyTemplate;
            }
            set
            {
                this._BodyTemplate = value;
            }
        }

        private string _From;
        /// <summary></summary>
        public string From
        {
            get { return _From; }
            set { _From = value; }
        }

        private string _To;
        /// <summary>
        /// comma or semicolon separated email address
        /// </summary>
        public string To
        {
            get { return _To; }
            set { _To = value; }
        }

        private string _CC;
        /// <summary></summary>
        public string CC
        {
            get
            {
                return this._CC;
            }
            set
            {
                this._CC = value;
            }
        }

        private string _Subject;
        /// <summary></summary>
        public string Subject
        {
            get { return _Subject; }
            set { _Subject = value; }
        }

        private string _SmtpServer;
        /// <summary></summary>
        public string SmtpServer
        {
            get { return _SmtpServer; }
            set { _SmtpServer = value; }
        }

        private string[] _Attachments;
        /// <summary></summary>
        public string[] Attachments
        {
            get { return _Attachments; }
            set { _Attachments = value; }
        }

        private string _UserName;
        /// <summary></summary>
        public string UserName
        {
            get { return _UserName; }
            set { _UserName = value; }
        }

        private string _Password;
        /// <summary></summary>
        public string Password
        {
            get { return _Password; }
            set { _Password = value; }
        }

        private bool _RequireAuthentication;
        /// <summary></summary>
        public bool RequireAuthentication
        {
            get { return _RequireAuthentication; }
            set { _RequireAuthentication = value; }
        }

        private MailPriority _Priority;
        /// <summary></summary>
        public MailPriority Priority
        {
            get { return _Priority; }
            set { _Priority = value; }
        }

        private bool _UseOutlookClient;
        /// <summary></summary>
        public bool UseOutlookClient
        {
            get
            {
                return this._UseOutlookClient;
            }
            set
            {
                this._UseOutlookClient = value;
            }
        }

        private bool _EnableSSL;
        /// <summary></summary>
        public bool EnableSSL
        {
            get
            {
                return this._EnableSSL;
            }
            set
            {
                this._EnableSSL = value;
            }
        }

        private Dictionary<string,string> _BodyPlaceHolders;
        /// <summary></summary>
        public Dictionary<string, string> BodyPlaceHolders
        {
            get
            {
                return this._BodyPlaceHolders;
            }
            set
            {
                this._BodyPlaceHolders = value;
            }
        }
        #endregion

        #region ctor
        /// <summary></summary>
        public EmailInstruction()
            :base(Guid.Empty, Guid.Empty)
        {
            this._SmtpServer = string.Empty;
            this._From = string.Empty;
            this._To = string.Empty;
            this._CC = string.Empty;
            this._Subject = string.Empty;
            this._Priority = MailPriority.Normal;
            this._RequireAuthentication = false;
            this._UserName = string.Empty;
            this._Password = string.Empty;
            this._Attachments = null;
            this._BodyTemplate = string.Empty;
            this._UseOutlookClient = false;
            this._EnableSSL = false;
            this._BodyPlaceHolders = new Dictionary<string, string>();
        }

        /// <summary></summary>
        public EmailInstruction(
            Guid componentID, 
            Guid jobTicketID,
            string smtpServer,
            string from,
            string to,
            string cc, 
            string subj,
            MailPriority priority,
            bool needAuthenticate,
            string userName,
            string password,
            string[] attachments,
            string bodyTemplate,
            bool useOutlook,
            bool enableSsl,
            Dictionary<string, string> placeHolders
            ) 
            : base(componentID, jobTicketID)
        {
            this._SmtpServer = smtpServer;
            this._From = from;
            this._To = to;
            this._CC = cc;
            this._Subject = subj;
            this._Priority = priority;
            this._RequireAuthentication = needAuthenticate;
            this._UserName = userName;
            this._Password = password;
            this._Attachments = attachments;
            this._BodyTemplate = bodyTemplate;
            this._UseOutlookClient = useOutlook;
            this._EnableSSL = enableSsl;
            this._BodyPlaceHolders = placeHolders;
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="xDoc"></param>
        /// <param name="parentNode"></param>
        /// <returns></returns>
        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode emailNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "SmtpServer", this.SmtpServer);
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "RequireAuthentication", this.RequireAuthentication.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "UserName", this.UserName);
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "Password", this.Password);
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "Priority", ((int)this.Priority).ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "From", this.From);
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "To", this.To);
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "CC", this.CC);
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "Subject", this.Subject);
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "BodyTemplate", this.BodyTemplate);
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode,"UseOutlook",this.UseOutlookClient.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, emailNode, "EnableSsl", this.EnableSSL.ToString());
            

            XmlNode attachmentNodes = XmlDataUtil.AddElement(ref xDoc, emailNode, "Attachments");
            if(this.Attachments !=null && this.Attachments.Length>0)
            {
                foreach(string filePath in this.Attachments)
                {
                    XmlNode fileNode = XmlDataUtil.AddElement(ref xDoc, attachmentNodes, "File");
                    XmlDataUtil.UpdateAttribute(ref xDoc,fileNode,"FilePath",filePath);
                }
            }
            
            if(this.BodyPlaceHolders !=null && this.BodyPlaceHolders.Count>0)
            {
                XmlNode placeHolderRootNode = XmlDataUtil.AddElement(ref xDoc, emailNode, "PlaceHolders");
                foreach(string placeHolderName in this.BodyPlaceHolders.Keys)
                {
                    XmlNode placeHolderNode = XmlDataUtil.AddElement(ref xDoc, placeHolderRootNode, "PlaceHolder");
                    XmlDataUtil.UpdateAttribute(ref xDoc, placeHolderNode, "Name", placeHolderName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, placeHolderNode, "Value",
                                                this.BodyPlaceHolders[placeHolderName]);
                }
            }

            return emailNode;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="xNode"></param>
        /// <returns></returns>
        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                EmailInstruction instruction = new EmailInstruction();
                instruction.OwnerComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                instruction.OwnerWorkerInstanceID = new Guid(xNode.Attributes.GetNamedItem("WorkerID").Value);
                instruction.SubmitTime = DateTime.Parse(xNode.Attributes.GetNamedItem("SubmitTime").Value);
                instruction.StartTime = DateTime.Parse(xNode.Attributes.GetNamedItem("StartTime").Value);

                instruction.SmtpServer = xNode.Attributes.GetNamedItem("SmtpServer").Value;
                instruction.RequireAuthentication =
                    bool.Parse(xNode.Attributes.GetNamedItem("RequireAuthentication").Value);
                instruction.UserName = xNode.Attributes.GetNamedItem("UserName").Value;
                instruction.Password = xNode.Attributes.GetNamedItem("Password").Value;
                instruction.Priority = (MailPriority) int.Parse(xNode.Attributes.GetNamedItem("Priority").Value);

                instruction.From = xNode.Attributes.GetNamedItem("From").Value;
                instruction.To = XmlDataUtil.GetAttributeValue(xNode, "To", "");
                instruction.CC = XmlDataUtil.GetAttributeValue(xNode, "CC", "");
                instruction.Subject = xNode.Attributes.GetNamedItem("Subject").Value;
                instruction.BodyTemplate = xNode.Attributes.GetNamedItem("BodyTemplate").Value;
                instruction.UseOutlookClient = bool.Parse(xNode.Attributes.GetNamedItem("UseOutlook").Value);
                instruction.EnableSSL = bool.Parse(xNode.Attributes.GetNamedItem("EnableSsl").Value);

                instruction.Attachments = null;
                XmlNodeList fileNodes = xNode.SelectNodes("Attachments/File");
                if(fileNodes !=null && fileNodes.Count>0)
                {
                    List<string> filePaths=new List<string>();
                    foreach(XmlNode fileNode in fileNodes)
                    {
                        string filePath = fileNode.Attributes.GetNamedItem("FilePath").Value;
                        filePaths.Add(filePath);
                    }
                    instruction.Attachments = filePaths.ToArray();
                }

                XmlNodeList placeHolderNodes = xNode.SelectNodes("PlaceHolders/PlaceHolder");
                if(placeHolderNodes !=null && placeHolderNodes.Count>0)
                {
                    instruction.BodyPlaceHolders = new Dictionary<string, string>();
                    foreach(XmlNode placeHodlerNode in placeHolderNodes)
                    {
                        string name = XmlDataUtil.GetAttributeValue(placeHodlerNode, "Name", "");
                        string value = XmlDataUtil.GetAttributeValue(placeHodlerNode, "Value", "");
                        instruction.BodyPlaceHolders.Add(name, value);
                    }
                }

                return instruction;
            }
            else
                throw new Exception("Unable to instantiate instruction: invalid type specified in xml node");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="excludeMemberFromTypes"></param>
        /// <returns></returns>
        public override Dictionary<string, Type> GetBindableMemberNames(Type[] excludeMemberFromTypes)
        {
            Dictionary<string,Type> bindableMembers = base.GetBindableMemberNames(excludeMemberFromTypes);
            if(this.BodyPlaceHolders !=null && this.BodyPlaceHolders.Count>0)
            {
                foreach(string placeHolderName in this.BodyPlaceHolders.Keys)
                {
                    bindableMembers.Add(placeHolderName,typeof(string));
                }
            }
            return bindableMembers;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="memberName"></param>
        /// <returns></returns>
        public override object ReadMemberValue(string memberName)
        {
            if(this.BodyPlaceHolders !=null && this.BodyPlaceHolders.Count>0)
            {
                foreach(string placeHolderName in this.BodyPlaceHolders.Keys)
                {
                    if (placeHolderName == memberName)
                        return this.BodyPlaceHolders[placeHolderName];
                }
            }
            return base.ReadMemberValue(memberName);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="memberName"></param>
        /// <param name="memberValue"></param>
        public override void SetMemberValue(string memberName, object memberValue)
        {
            if (this.BodyPlaceHolders != null && this.BodyPlaceHolders.Count > 0)
            {
                foreach (string placeHolderName in this.BodyPlaceHolders.Keys)
                {
                    if (placeHolderName == memberName)
                    {
                        this.BodyPlaceHolders[placeHolderName] = memberValue == null ? null : memberValue.ToString();
                        return;
                    }
                }
            }
            base.SetMemberValue(memberName, memberValue);
        }
    }
}
